﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

using GreyGate.Utils;
using GreyGate.Screens;

namespace GreyGate.Objects
{
    class Player
    {
        private GraphicsDeviceManager graphics;
        private ContentManager content;
        private DrawModel drawModel;

        private Player opponent;

        private Model figure;
        private Matrix[] bones;
        private Vector3 lookPosFig;
        private Matrix lookAtFig;
        private Vector3 positionFig;
        private float figureScale;

        private Viewport view;
        private Vector3 cameraPosition;
        private Vector3 lastPosition;
        private Matrix lookAt;
        private float lookAngle;
        private float lastRotation;
        private float lookRotation = 2f;
        private Vector3 lookPos;
        private const float lookAheadValue = 1f;

        // currentPos speicher die Koordinaten in [z,x]
        private int[] currentPos;
        private int X,Z;        
        private bool rotatesLeft,
                     rotatesRight,
                     turnsAround,
                     movesForward,
                     movesBack;

        private int labyrinthSize;
        private float stepSize = 20f;

        public Player( GraphicsDeviceManager graphics, ContentManager content, 
                       Viewport view, int[] startPos, int labyrinthSize)
        {
            this.graphics = graphics;
            this.content = content;
            this.view = view;
            
            this.currentPos = startPos;
            this.labyrinthSize = labyrinthSize;
            initialize();
            LoadContent();
        }

        public void setOpponent(ref Player opponent)
        {
            this.opponent = opponent;
        }

        public void initialize()
        {

            drawModel = new DrawModel();

            Vector3 posZero = new Vector3( 0 - (UtilityVariables.stepSizeRooms) * (labyrinthSize - (labyrinthSize/2)),
                                           30,
                                           0 - (UtilityVariables.stepSizeRooms) * (labyrinthSize - (labyrinthSize/2)) );

           // Vector3 posZero = Vector3.Zero;
            cameraPosition = posZero;

            cameraPosition.X += UtilityVariables.stepSizeRooms * currentPos[1];
            cameraPosition.Z += UtilityVariables.stepSizeRooms * currentPos[0];

            lookPos = cameraPosition;
            lastPosition = cameraPosition;
            lookPos.Z -= lookAheadValue;
            //lookPos.Y = 0;

            lookAt = Matrix.CreateLookAt( cameraPosition,
                                          lookPos,
                                          Vector3.Up);

            lookPosFig = cameraPosition;
            lookPosFig.Z += 1;
            lookAtFig = Matrix.CreateLookAt(cameraPosition,
                                            lookPosFig,
                                            Vector3.Up);

            positionFig = new Vector3(0,-2.5f,+30);
            figureScale = UtilityVariables.scale ;

            X = 0;
            Z = 0;

            RotatesLeft = false;
            RotatesRight = false;
            TurnsAround = false;
            MovesForward = false;
            MovesBack = false;
            
            lookAngle = 0;
            lastRotation = lookAngle;
            
        }

        public void LoadContent()
        {
            figure = content.Load<Model>("Models//figure");
            bones = new Matrix[figure.Bones.Count];
        }

        public void update(Room room)
        {
           playerDoesRotation(room);
        }

        public void draw(Room[,] labyrinth)
        {
            // setzen des Screens dieses Spielers.
            graphics.GraphicsDevice.Viewport = View;

            #region labyrinth drawing

                         drawModel.Draw(labyrinth[currentPos[0], currentPos[1]].getRoom,
                                        labyrinth[currentPos[0], currentPos[1]].Bones,
                                        lookAt,
                                        UtilityVariables.fieldOfView,
                                        labyrinth[currentPos[0], currentPos[1]].getLocation(),
                                        UtilityVariables.scale,
                                        0);
                         if (currentPos[0] - 1 >= 0 && labyrinth[currentPos[0] - 1, currentPos[1]] != null)
                         {
                             drawModel.Draw(labyrinth[currentPos[0]-1, currentPos[1]].getRoom,
                                                     labyrinth[currentPos[0] - 1, currentPos[1]].Bones,
                                                     lookAt,
                                                     UtilityVariables.fieldOfView,
                                                     labyrinth[currentPos[0] - 1, currentPos[1]].getLocation(),
                                                     UtilityVariables.scale,0);

                                                   
                             if (labyrinth[currentPos[0] - 1, currentPos[1]].getLocation().Y == opponent.currentPos[0] &&
                                 labyrinth[currentPos[0] - 1, currentPos[1]].getLocation().X == opponent.currentPos[1] -1){}
                             

                         }

                         if (currentPos[0] - 2 >= 0 && labyrinth[currentPos[0] - 2, currentPos[1]] != null)
                         drawModel.Draw(labyrinth[currentPos[0]-2, currentPos[1]].getRoom,
                                                     labyrinth[currentPos[0] - 2, currentPos[1]].Bones,
                                                     lookAt,
                                                     UtilityVariables.fieldOfView,
                                                     labyrinth[currentPos[0] - 2, currentPos[1]].getLocation(),
                                                     UtilityVariables.scale,
                                                     0);
                         if (currentPos[0] + 1 < UtilityVariables.labyrinthSize && labyrinth[currentPos[0] + 1, currentPos[1]] != null)
                         {
                             drawModel.Draw(labyrinth[currentPos[0]+1, currentPos[1]].getRoom,
                                                     labyrinth[currentPos[0] + 1, currentPos[1]].Bones,
                                                     lookAt,
                                                     UtilityVariables.fieldOfView,
                                                     labyrinth[currentPos[0] + 1, currentPos[1]].getLocation(),
                                                     UtilityVariables.scale,
                                                     0);                             
                         }

                         if (currentPos[0] + 2 < UtilityVariables.labyrinthSize && labyrinth[currentPos[0] + 2, currentPos[1]] != null)
                         drawModel.Draw(labyrinth[currentPos[0]+2, currentPos[1]].getRoom,
                                                     labyrinth[currentPos[0] + 2, currentPos[1]].Bones,
                                                     lookAt,
                                                     UtilityVariables.fieldOfView,
                                                     labyrinth[currentPos[0] + 2, currentPos[1]].getLocation(),
                                                     UtilityVariables.scale,
                                                     0);

                         if (currentPos[1] - 1 >= 0 && labyrinth[currentPos[0], currentPos[1] - 1] != null)
                             drawModel.Draw(labyrinth[currentPos[0], currentPos[1] - 1].getRoom,
                                                         labyrinth[currentPos[0], currentPos[1] - 1].Bones,
                                                         lookAt,
                                                         UtilityVariables.fieldOfView,
                                                         labyrinth[currentPos[0], currentPos[1] - 1].getLocation(),
                                                         UtilityVariables.scale,
                                                         0);
                         if (currentPos[1] - 2 >= 0 && labyrinth[currentPos[0], currentPos[1] - 2] != null)
                             drawModel.Draw(labyrinth[currentPos[0], currentPos[1] - 2].getRoom,
                                                         labyrinth[currentPos[0], currentPos[1] - 2].Bones,
                                                         lookAt,
                                                         UtilityVariables.fieldOfView,
                                                         labyrinth[currentPos[0], currentPos[1] - 2].getLocation(),
                                                         UtilityVariables.scale,
                                                         0);
                         if (currentPos[1] + 1 < UtilityVariables.labyrinthSize && labyrinth[currentPos[0], currentPos[1] +1] != null)
                             drawModel.Draw(labyrinth[currentPos[0], currentPos[1] + 1].getRoom,
                                                         labyrinth[currentPos[0], currentPos[1] + 1].Bones,
                                                         lookAt,
                                                         UtilityVariables.fieldOfView,
                                                         labyrinth[currentPos[0], currentPos[1] + 1].getLocation(),
                                                         UtilityVariables.scale,
                                                         0);
                         if (currentPos[1] + 2 < UtilityVariables.labyrinthSize && labyrinth[currentPos[0], currentPos[1] + 2] != null)
                             drawModel.Draw(labyrinth[currentPos[0], currentPos[1] + 2].getRoom,
                                                         labyrinth[currentPos[0], currentPos[1] + 2].Bones,
                                                         lookAt,
                                                         UtilityVariables.fieldOfView,
                                                         labyrinth[currentPos[0], currentPos[1] + 2].getLocation(),
                                                         UtilityVariables.scale,
                                                         0);
            #endregion

                         drawOpponent(labyrinth);
                         
        }

        private void drawOpponent(Room[,] labyrinth)
        {
            // Fehler hier
            
            
            if ((currentPos[0] - 1 >= 0 &&
                labyrinth[currentPos[0], currentPos[1]] != null &&
                labyrinth[currentPos[0], currentPos[1]].getPosition.Y - 1 == opponent.currentPos[0] &&
                labyrinth[currentPos[0], currentPos[1]].getPosition.X == opponent.currentPos[1]) )
            {
                    drawModel.Draw(figure, bones,
                                        lookAt,
                                        UtilityVariables.fieldOfView,
                                        labyrinth[currentPos[0] - 1, currentPos[1]].getLocation(),
                                        figureScale, 0);
            }

            if ((currentPos[1] < UtilityVariables.labyrinthSize &&
                labyrinth[currentPos[0], currentPos[1]] != null &&
                labyrinth[currentPos[0], currentPos[1]].getPosition.Y == opponent.currentPos[0] &&
                labyrinth[currentPos[0], currentPos[1]].getPosition.X + 1 == opponent.currentPos[1])
                )
            {
                drawModel.Draw(figure, bones,
                                    lookAt,
                                    UtilityVariables.fieldOfView,
                                    labyrinth[currentPos[0], currentPos[1] + 1].getLocation(),
                                    figureScale, 0);
            }

            if (
                (currentPos[1] - 1 >= 0 &&
                labyrinth[currentPos[0], currentPos[1]] != null &&
                labyrinth[currentPos[0], currentPos[1]].getPosition.Y == opponent.currentPos[0] &&
                labyrinth[currentPos[0], currentPos[1]].getPosition.X - 1 == opponent.currentPos[1]))
            {
                drawModel.Draw(figure, bones,
                                    lookAt,
                                    UtilityVariables.fieldOfView,
                                    labyrinth[currentPos[0], currentPos[1]-1].getLocation(),
                                    figureScale, 0);
            }

            if (
                (currentPos[0] + 1 < UtilityVariables.labyrinthSize &&
                labyrinth[currentPos[0], currentPos[1]] != null &&
                labyrinth[currentPos[0], currentPos[1]].getPosition.Y + 1 == opponent.currentPos[0] &&
                labyrinth[currentPos[0], currentPos[1]].getPosition.X == opponent.currentPos[1]))
            {
                drawModel.Draw(figure, bones,
                                    lookAt,
                                    UtilityVariables.fieldOfView,
                                    labyrinth[currentPos[0] + 1, currentPos[1]].getLocation(),
                                    figureScale, 0);
            }
        }

        public void playerDoesRotation(Room room)
        {
            #region player actions
            if (RotatesLeft)
            {
                lookAngle += lookRotation;
                if (lookAngle >= 360)
                {
                    lookAngle -= 360;
                    lastRotation -= 360;
                }
                if(lookAngle >= lastRotation+90){
                    lookAngle = lastRotation + 90;
                    lastRotation = lookAngle;
                    RotatesLeft = false;
                    Console.WriteLine("player1: " + currentPos[1] + "," + currentPos[0]);
                    Console.WriteLine("player2: " + opponent.currentPos[1] + "," + opponent.currentPos[0]);
                }

                lookPos.Z = cameraPosition.Z - (float)Math.Cos( MathHelper.ToRadians( lookAngle ) ) * lookAheadValue;
                lookPos.X = cameraPosition.X - (float)Math.Sin( MathHelper.ToRadians( lookAngle ) ) * lookAheadValue;

                lookAt = Matrix.CreateLookAt( cameraPosition,
                                              lookPos,
                                              Vector3.Up);
            }

            if (RotatesRight)
            {
                lookAngle -= lookRotation;
                if (lookAngle < 0)
                {
                    lookAngle += 360;
                    lastRotation += 360;
                }
                if (lookAngle <= lastRotation - 90)
                {
                    lookAngle = lastRotation - 90;
                    lastRotation = lookAngle;
                    RotatesRight = false;
                    Console.WriteLine("player1: " + currentPos[1] + "," + currentPos[0]);
                    Console.WriteLine("player2: " + opponent.currentPos[1] + "," + opponent.currentPos[0]);
                }

                lookPos.Z = cameraPosition.Z - (float)Math.Cos(MathHelper.ToRadians(lookAngle)) * lookAheadValue;
                lookPos.X = cameraPosition.X - (float)Math.Sin(MathHelper.ToRadians(lookAngle)) * lookAheadValue;
                
                lookAt = Matrix.CreateLookAt(cameraPosition,
                                              lookPos,
                                              Vector3.Up);
            }

            if (TurnsAround)
            {
                lookAngle -= lookRotation*2;
                if (lookAngle < 0)
                {
                    lookAngle += 360;
                    lastRotation += 360;
                }
                if (lookAngle <= lastRotation - 180)
                {
                    lookAngle = lastRotation - 180;
                    lastRotation = lookAngle;
                    turnsAround = false;
                    Console.WriteLine("player1: " + currentPos[1] + "," + currentPos[0]);
                    Console.WriteLine("player2: " + opponent.currentPos[1] + "," + opponent.currentPos[0]);
                }

                lookPos.Z = cameraPosition.Z - (float)Math.Cos(MathHelper.ToRadians(lookAngle)) * lookAheadValue;
                lookPos.X = cameraPosition.X - (float)Math.Sin(MathHelper.ToRadians(lookAngle)) * lookAheadValue;

                lookAt = Matrix.CreateLookAt(cameraPosition,
                                              lookPos,
                                              Vector3.Up);
            }

            if (MovesForward)
            {
                if (lookAngle / 90 == 0 && !room.MovesFront)
                {
                    MovesForward = false;
                    return;
                }

                if (lookAngle / 90 == 1 && !room.MovesLeft)
                {
                    MovesForward = false;
                    return;
                }

                if (lookAngle / 90 == 2 && !room.MovesBack)
                {
                    MovesForward = false;
                    return;
                }

                if (lookAngle / 90 == 3 && !room.MovesRight)
                {
                    MovesForward = false;
                    return;
                }

                if (lookAngle / 90 == 0)
                {

                    cameraPosition.Z -= stepSize;
                    lookPos.Z -= stepSize;
                    if (cameraPosition.Z <= lastPosition.Z - UtilityVariables.stepSizeRooms)
                    {
                        cameraPosition.Z = lastPosition.Z - UtilityVariables.stepSizeRooms;
                        lastPosition = cameraPosition;
                        currentPos[0] -= 1;
                        movesForward = false;
                        Console.WriteLine("player1: " + currentPos[1] + "," + currentPos[0]);
                        Console.WriteLine("player2: " + opponent.currentPos[1] + "," + opponent.currentPos[0]);
                    }
                }

                if (lookAngle / 90 == 1)
                {
                    cameraPosition.X -= stepSize;
                    lookPos.X -= stepSize;
                    if (cameraPosition.X <= lastPosition.X - UtilityVariables.stepSizeRooms)
                    {
                        cameraPosition.X = lastPosition.X - UtilityVariables.stepSizeRooms;
                        lastPosition = cameraPosition;
                        currentPos[1] -= 1;
                        movesForward = false;
                        Console.WriteLine("player1: " + currentPos[1] + "," + currentPos[0]);
                        Console.WriteLine("player2: " + opponent.currentPos[1] + "," + opponent.currentPos[0]);
                    }
                }

                if (lookAngle / 90 == 2)
                {
                    cameraPosition.Z += stepSize;
                    lookPos.Z += stepSize;
                    if (cameraPosition.Z >= lastPosition.Z + UtilityVariables.stepSizeRooms)
                    {
                        cameraPosition.Z = lastPosition.Z + UtilityVariables.stepSizeRooms;
                        lastPosition = cameraPosition;
                        currentPos[0] += 1;
                        movesForward = false;
                        Console.WriteLine("player1: " + currentPos[1] + "," + currentPos[0]);
                        Console.WriteLine("player2: " + opponent.currentPos[1] + "," + opponent.currentPos[0]);
                    }
                }

                if (lookAngle / 90 == 3)
                {
                    cameraPosition.X += stepSize;
                    lookPos.X += stepSize;
                    if (cameraPosition.X >= lastPosition.X + UtilityVariables.stepSizeRooms)
                    {
                        cameraPosition.X = lastPosition.X + UtilityVariables.stepSizeRooms;
                        lastPosition = cameraPosition;
                        currentPos[1] += 1;
                        movesForward = false;
                        Console.WriteLine("player1: " + currentPos[1] + "," + currentPos[0]);
                        Console.WriteLine("player2: " + opponent.currentPos[1] + "," + opponent.currentPos[0]);
                    }
                }
                lookAt = Matrix.CreateLookAt(cameraPosition,
                                              lookPos,
                                              Vector3.Up);
            }

            if (MovesBack)
            {
                if (lookAngle / 90 == 0 && !room.MovesBack)
                {
                    MovesBack = false;
                    return;
                }

                if (lookAngle / 90 == 1 && !room.MovesRight)
                {
                    MovesBack = false;
                    return;
                }

                if (lookAngle / 90 == 2 && !room.MovesFront)
                {
                    MovesBack = false;
                    return;
                }

                if (lookAngle / 90 == 3 && !room.MovesLeft)
                {
                    MovesBack = false;
                    return;
                }
                if (lookAngle / 90 == 0)
                {
                    cameraPosition.Z += stepSize;
                    lookPos.Z -= stepSize;
                    if (cameraPosition.Z >= lastPosition.Z + UtilityVariables.stepSizeRooms)
                    {
                        cameraPosition.Z = lastPosition.Z + UtilityVariables.stepSizeRooms;
                        lastPosition = cameraPosition;
                        currentPos[0] += 1;
                        movesBack = false;
                        Console.WriteLine("player1: " + currentPos[1] + "," + currentPos[0]);
                        Console.WriteLine("player2: " + opponent.currentPos[1] + "," + opponent.currentPos[0]);
                    }
                }

                if (lookAngle / 90 == 1)
                {
                    cameraPosition.X += stepSize;
                    lookPos.X -= stepSize;
                    if (cameraPosition.X >= lastPosition.X + UtilityVariables.stepSizeRooms)
                    {
                        cameraPosition.X = lastPosition.X + UtilityVariables.stepSizeRooms;
                        lastPosition = cameraPosition;
                        currentPos[1] += 1;
                        movesBack = false;
                        Console.WriteLine("player1: " + currentPos[1] + "," + currentPos[0]);
                        Console.WriteLine("player2: " + opponent.currentPos[1] + "," + opponent.currentPos[0]);
                    }
                }

                if (lookAngle / 90 == 2)
                {
                    cameraPosition.Z -= stepSize;
                    lookPos.Z += stepSize;
                    if (cameraPosition.Z <= lastPosition.Z - UtilityVariables.stepSizeRooms)
                    {
                        cameraPosition.Z = lastPosition.Z - UtilityVariables.stepSizeRooms;
                        lastPosition = cameraPosition;
                        currentPos[0] -= 1;
                        movesBack = false;
                        Console.WriteLine("player1: " + currentPos[1] + "," + currentPos[0]);
                        Console.WriteLine("player2: " + opponent.currentPos[1] + "," + opponent.currentPos[0]);
                    }
                }

                if (lookAngle / 90 == 3)
                {
                    cameraPosition.X -= stepSize;
                    lookPos.X += stepSize;
                    if (cameraPosition.X <= lastPosition.X - UtilityVariables.stepSizeRooms)
                    {
                        cameraPosition.X = lastPosition.X - UtilityVariables.stepSizeRooms;
                        lastPosition = cameraPosition;
                        currentPos[1] -= 1;
                        movesBack = false;
                        Console.WriteLine("player1: " + currentPos[1] + "," + currentPos[0]);
                        Console.WriteLine("player2: " + opponent.currentPos[1] + "," + opponent.currentPos[0]);
                    }
                }

                lookAt = Matrix.CreateLookAt(cameraPosition,
                                              lookPos,
                                              Vector3.Up);
            }
            #endregion
        }

        #region Getter und Setter
        public Viewport View
        {
            get { return view; }
            set { view = value; }
        }

        public Vector3 CameraPosition
        {
            get { return cameraPosition; }
        }

        public Matrix LookAt
        {
            get { return lookAt; }
        }

        public int[] CurrentPos 
        {
            get { return currentPos; }
        }

        public bool RotatesLeft
        {
            get { return rotatesLeft; }
            set { rotatesLeft = value; }
        }

        public bool RotatesRight
        {
            get { return rotatesRight; }
            set { rotatesRight = value; }
        }

        public bool TurnsAround
        {
            get { return turnsAround; }
            set { turnsAround = value; }
        }

        public bool MovesForward
        {
            get { return movesForward; }
            set { movesForward = value; }
        }

        public bool MovesBack
        {
            get { return movesBack; }
            set { movesBack = value; }
        }
        #endregion

        #region Keyboard
        public void checkForKeyboard()
        {
            if (ScreenManager.kb.Left)
            {
                rotatesLeft = true;
            }

            if (ScreenManager.kb.Right)
            {
                rotatesRight = true;
            }

            if (ScreenManager.kb.Up)
            {                
                movesForward= true;
            }

            if (ScreenManager.kb.Down)
            {
                movesBack = true;
            }
        }
        #endregion
    }
}
